var _geometry = require('core/glm.js');
var _matrix4 = _geometry.matrix4;
var _v2 = _geometry.vec2f;
var _v3 = _geometry.vec3f;
var _glm = _geometry.glm;

/**
 * help setup points mesh
 *
 * @param buf
 * @param element
 * @param accp
 * @param acct
 * @param frame
 * @constructor
 */
function Filler(element, accp, acct, frame) {
    this.element = element;
    this.accp = accp;
    this.acct = acct;
    this.v = new _v3();
    this.t = new _v2();
    this.frame = frame;

    this.fmatrix = new _matrix4();
    frame.getMatrix(this.fmatrix);
    this.matrix = new _matrix4(this.fmatrix);

    this.mCursor = 0;
}
/**
 * copy data to other buffer
 *
 * @param from
 * @param buffer
 * @param to
 * @param length
 */
Filler.prototype.copyBuffer = function (from, findex, to, tindex, length) {
    var buf = from;
    var element = this.element;
    for (var i = length - 1; i >= 0; i--) {
        buf.getElement(findex + i, element);
        to.setElement(tindex + i, element);
    }
};
/**
 * copy data to current cursor
 * @param from
 * @param length
 */
Filler.prototype.appendCopy = function (from, length) {
    if (arguments.length == 1) {
        length = 1;
    }
    this.copyPoint(from, this.mCursor, length);
    this.mCursor += length;
}
Filler.prototype.copyPoint = function (from, to, length) {
    if (arguments.length == 2) {
        length = 1;
    }
    var buf = this.buf;
    var sget = buf.getElement;
    var sset = buf.setElement;
    var element = this.element;

    for (var i = length - 1; i >= 0; i--) {
        sget.call(buf, from + i, element);
        sset.call(buf, to + i, element);
    }
};
Filler.prototype.appendRect = function (x1, y1, x2, y2) {
    var current = this.mCursor;
    this.appendPoint(x1, y1);
    this.appendPoint(x1, y2);
    this.appendPoint(x2, y1);
    this.appendCopy(current + 1);
    this.appendPoint(x2, y2);
    this.appendCopy(current + 2);
};
Filler.prototype.appendRectV = function (x1, y1, x2, y2) {
    var current = this.mCursor;
    this.appendPoint(x2, y1);
    this.appendPoint(x1, y1);
    this.appendPoint(x2, y2);
    this.appendCopy(current + 1);
    this.appendPoint(x1, y2);
    this.appendCopy(current + 2);
};
Filler.prototype.appendPoint = function (x, y) {
    var v = this.v;
    this.frame.getPointAbs(v, this.t, x, y);
    _glm.mulMV3(v, this.matrix, v);

    this.acct.set(this.t);
    this.accp.set(v);
    this.buf.setElement(this.mCursor, this.element);
    this.mCursor++;
};
/**
 * @param matrix
 * @param from from buffer
 * @param findex
 * @param to to buffer
 * @param tindex
 * @param length
 */
Filler.prototype.transform = function (matrix, from, findex, to, tindex, length) {
    var buf = from;
    var element = this.element;
    var v = this.v;
    var acc = this.accp;

    for (var i = length - 1; i >= 0; i--) {
        buf.getElement(findex + i, element);
        acc.get(v);
        _glm.mulMV3(v, matrix, v);
        acc.set(v);
        to.setElement(tindex + i, element);
    }
};
/**
 * @param matrix
 * @param findex
 * @param to to buffer
 * @param tindex
 * @param length
 */
Filler.prototype.transformLocal = function (matrix, findex, to, tindex, length) {
    var buf = this.buf;
    var element = this.element;
    var v = this.v;
    var acc = this.accp;

    for (var i = length - 1; i >= 0; i--) {
        buf.getElement(findex + i, element);
        acc.get(v);
        _glm.mulMV3(v, matrix, v);
        acc.set(v);
        to.setElement(tindex + i, element);
    }
};
Filler.prototype.skip = function (l) {
    this.mCursor += l;
};
Filler.prototype.seek = function (l) {
    this.mCursor = l;
};
Filler.prototype.getPointer = function () {
    return this.mCursor;
};
Filler.prototype.getMatrix = function () {
    return this.matrix;
};
Filler.prototype.setMatrix = function (matrix) {
    _glm.mulMM(this.matrix, matrix, this.fmatrix);
};
Filler.prototype.getBuffer = function () {
    return this.buf;
};
Filler.prototype.setBuffer = function (buf) {
    this.buf = buf;
};

/**
 * create with structure
 *
 * @param structure
 * @param frame
 * @returns {Filler}
 */
Filler.createFiller = function (structure, frame) {
    return new Filler(structure.buffer(), structure.field('p'), structure.field('t'), frame);
};

module.exports = Filler;